
class MediaInfo {
    constructor() {
        this.mimeType = null
        this.duration = null

        this.hasAudio = null
        this.hasVideo = null
        this.audioCodec = null
        this.videoCodec = null
        this.audioDataDate = null
        this.videoDataDate = null

        this.audioSampleRate = null
        this.audioChannelCount = null

        this.width = null
        this.height = null
        this.fps = null
        this.profile = null
        this.level = null
        this.refFrames = null
        this.chromaFormat = null
        this.sarNum = null
        this.sarDen = null

        this.metadata = null
        this.segments = null // MediaInfo[]
        this.segmentCount = null
        this.hasKeyframesIndex = null
        this.keyframesIndex = null
    }

    isComplete() {
        let audioInfoComplete = 
            (this.hasAudio === false) ||
            (
                this.hasAudio === true &&
                this.audioCodec != null &&
                this.audioSampleRate != null &&
                this.audioChannelCount != null
            )
        
        let videoInfoComplete = 
            (this.hasVideo === false) ||
            (
                this.hasVideo === true &&
                this.videoCodec != null &&
                this.width != null &&
                this.height != null &&
                this.fps != null &&
                this.profile != null &&
                this.level != null &&
                this.refFrames != null &&
                this.chromaFormat != null &&
                this.sarNum != null &&
                this.sarDen != null
            )
        
        // keyframesIndex may not be present
        return (
            this.mimeType != null &&
            this.duration != null &&
            this.metadata != null &&
            this.hasKeyframesIndex != null &&
            audioInfoComplete &&
            videoInfoComplete
        )
    }

    isSeekable() {
        return this.hasKeyframesIndex === true
    }

    getNearestKeyframe(milliseconds) {
        if (this.keyframesIndex == null) {
            return null
        }

        let table = this.keyframesIndex
        let keyframeIdx = this._search(table.times, milliseconds)

        return {
            index: keyframeIdx,
            milliseconds: table.times[keyframeIdx],
            fileposition: table.filepositions[keyframeIdx]
        }
    }

    _search(list, value) {
        let idx = 0

        let last = list.length - 1
        let mid = 0
        let lbound = 0
        let ubound = last

        if (value < list[0]) {
            idx = 0
            lbound = ubound + 1 // skip search
        }

        while (lbound <= ubound) {
            mid = lbound + Math.floor((ubound - lbound) / 2)
            if (
                mid === last ||
                (
                    value >= list[mid] &&
                    value < list[mid + 1]
                )
            ) {
                idx = mid
                break
            } else if (list[mid] < value) {
                lbound = mid + 1
            } else {
                ubound = mid - 1
            }
        }
        return idx
    }
}